﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.Xml;
using Core.Module.Interfaces;
using Core.Module.Interfaces.Controller;
using Core.Module.Interfaces.Model;
using Module.DefaultContent.Interfaces;
using umbraco;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic;
using umbraco.cms.businesslogic.property;
using umbraco.cms.businesslogic.web;
using umbraco.interfaces;
using umbraco.presentation;
using Core.Module;
using Module.MultiSiteFields.Interfaces;

namespace Module.DefaultContent
{
    public class DefaultContentModule : IDefaultContentModule, IModule
	{
		public string Id
		{
			get { return "7A24EBC6-52AB-48DA-B1D4-FC832DE527D3"; }
		}

		public string Alias
		{
			get { return "DefaultContentModule"; }
		}

		public string Title
		{
			get { return ui.Text("multisite","Module_" + Alias); }
		}

		public bool Enabled { get; set; }
		public bool Active { get; set; }
		public int Position { get; set; }
		public XmlElement Settings { get; set; }

		public ISite Site { get; set; }
		public IModuleNode Defaults { get; set; }
		INodeController<IFrontend> NodeController { get; set; }

		public void Init(ISite site)
		{
			Site = site;
			NodeController = ObjectManager.Resolve<INodeController<IFrontend>>();
			if (site.Settings!=null) Defaults = NodeController.GetPropertyAsNode(site.Settings, "defaultsId");
			if (Defaults == null) Defaults = NodeController.GetChild(site.Settings.Id, "Defaults");
            if (Defaults != null)
            {
                Document.New +=
                (d, e) =>
                {
                    string[] path = (d.Path ?? "").Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                    if (Enabled && path.Length > 1 && Site.Node.Id.Equals(path[1])) Document_New(d, e);
                };

                UmbracoDefault.BeforeRequestInit += (s, e) =>
                {
                    if (Enabled && !UmbracoContext.Current.LiveEditingContext.Enabled) return;
                    IModuleNode pNode = NodeController.Get(e.PageId.ToString());
                    if (!pNode.SiteId.Equals(Site.Node.Id)) return;
                    UmbracoDefault_BeforeRequestInit(s, e, pNode);
                };
                GenerateDefaultNodes(DocumentType.GetByAlias("Pages"));
                RegisterTreeStartPoints();
            }
            else EnsureModuleUmbracoSettings();

		}

        private void RegisterTreeStartPoints()
        {
            IStartPointsController startPoints = ObjectManager.Resolve<IStartPointsController>();
            startPoints.Register("content","Site.PageDefaults", (point,forNode) =>
            {
                if (forNode == null || !Site.Node.Id.Equals(forNode.SiteId)) return false;
                startPoints.SetValue(point, "StartFrom", Defaults.Id);
                return true;
            });
        }

        public IModuleNode GetDefault(IModuleNode forNode)
        {
            if (Defaults == null || forNode == null) return null;            
            return GetDefault(forNode.Alias);
        }
              

		#region auto fill default content
		private void Document_New(Document sender, NewEventArgs e)
		{
			IModuleNode defaultNode = GenerateDefaultNode(sender.ContentType.Alias,true);
			Property p;
			if (defaultNode != null)
			{
				XmlElement defProps = Settings != null ? Settings : (XmlElement)umbraco.UmbracoSettings.GetKeyAsNode("ism/defaults/properties");
				if (defProps != null)
					foreach (XmlElement item in defProps.SelectNodes("property[string-length(@name)>0]"))
						if (item.SelectNodes("exclude[@alias='" + sender.ContentType.Alias + "']").Count < 1)
						{
							string alias = item.GetAttribute("name");
							p = sender.getProperty(alias);
							if (p != null) ReplacePropertyValue(p, NodeController.GetPropertyValue(defaultNode, alias), sender);
						}
			}
			//title if empty node-name
			p = sender.getProperty("title");
			if (p != null && string.IsNullOrEmpty(Convert.ToString(p.Value))) p.Value = sender.Text;
		}
        private IModuleNode GetDefault(string nodeAlias)
        {
            IModuleNode result = NodeController.GetChild(Defaults.Id, nodeAlias);
            return result;
        }
		private IModuleNode GenerateDefaultNode(string documentTypeAlais,bool justGet)
		{
            IModuleNode result = GetDefault(documentTypeAlais);
            if (result != null || justGet) return result;
            result=ObjectManager.Resolve<INodeController<IBackOffice>>().GetChild(Defaults.Id, documentTypeAlais);
            if (result != null) return result;
            try
            {
                Document d = Document.MakeNew(
                    string.Concat("Default - ", documentTypeAlais),
                    DocumentType.GetByAlias(documentTypeAlais),
                    User.GetCurrent(),
                    int.Parse(Defaults.Id)
                );
                Property p = d.getProperty("title");
                if (p != null) p.Value = "%%name%%";
                d.Save();
                //d.PublishWithResult(User.GetCurrent());   --can't publish - don't have access to the user context yet
            }
            catch (Exception ex)
            {
                Log.Add(LogTypes.Error,-1, "DefaultContentModule: Can't generate default document for:" + documentTypeAlais + "\r\n<br/>" + ex.Message + "\r\n<br/>" + ex.StackTrace);
            }
			return null;
		}

		private void GenerateDefaultNodes(DocumentType parentDType)
		{
			if (parentDType == null) return;
			List<DocumentType> allDTypes = DocumentType.GetAllAsList();
			foreach (DocumentType cDType in allDTypes.Where(dti => dti.MasterContentType.Equals(parentDType.Id)))
			{
				GenerateDefaultNode(cDType.Alias,false);
				GenerateDefaultNodes(cDType);
			}
		}

		public virtual void ReplacePropertyValue(Property forProperty, object defaultValue, Content curPage)
		{
			if (defaultValue == null) return;///return current value if default is null
			Regex rx = new Regex("%%([^%%]*)%%");

			string stringdata = Convert.ToString(defaultValue);
			MatchCollection matches = rx.Matches(stringdata ?? "");

			if (matches.Count == 0) forProperty.Value = defaultValue;//no masks - just static data
			else
			{//enter dynamic data
				StringBuilder result = new StringBuilder(stringdata);
				foreach (Match match in matches)
				{
					string key = match.Groups[1].Value;
					string resvalue = System.Convert.ToString(GetPageData(curPage, key));
					result.Replace("%%" + key + "%%", resvalue);
				}
				forProperty.Value = result.ToString();
			}
		}

		public object GetPageData(Content page, string datakey)
		{
			if ("name".Equals(datakey, StringComparison.CurrentCultureIgnoreCase)) return page.Text;
			if ("parent".Equals(datakey, StringComparison.CurrentCultureIgnoreCase) && page.ParentId > -1) return page.Parent.Text;
			if ("alias".Equals(datakey, StringComparison.CurrentCultureIgnoreCase)) return page.ContentType.Alias;
			if ("id".Equals(datakey, StringComparison.CurrentCultureIgnoreCase)) return page.Id;
			if ("icon".Equals(datakey, StringComparison.CurrentCultureIgnoreCase)) return page.ContentTypeIcon;
			Property p = page.getProperty(datakey);
			if (p != null) return p.Value;

			return "%%can't replace:" + datakey + "%";
		}


		#endregion

		#region Add Buttons To Live Editing Panel
		private void UmbracoDefault_BeforeRequestInit(object sender, RequestInitEventArgs e, IModuleNode pageNode)
		{

			Page curPage = sender as Page;
			if (curPage == null) return;
			AddScriptsToPage();
			AddPageEditButton(pageNode);
			AddPageDefaultsEditButon(pageNode);
			AddSiteEditButton();
		}

		private void AddSiteEditButton()
		{            //site edit button            
            AddButtonToLiveEditingPannel(Site.Node.Id, "Site: " + (string.IsNullOrEmpty(Site.Node.Title) ? Site.Node.Name : Site.Node.Title), GetNodeIcon(Site.Node, "/umbraco/images/umbraco/editSite.png"), "Site", "data");
		}

		private void AddPageDefaultsEditButon(IModuleNode pageNode)
		{

			IModuleNode defaultNode = NodeController.GetChild(Defaults.Id, pageNode.Alias);
			if (defaultNode != null)
				AddButtonToLiveEditingPannel(defaultNode.Id,
					string.Format("Defaults for: {0}, {1}", string.IsNullOrEmpty(pageNode.Title) ? pageNode.Name : pageNode.Title, defaultNode.Name),
					"/umbraco/images/umbraco/editDefault.png",
					"Defaults", "for page:" + pageNode.Name);
		}

		private void AddPageEditButton(IModuleNode pageNode)
		{
			AddButtonToLiveEditingPannel(pageNode.Id,
				  string.IsNullOrEmpty(pageNode.Title) ? pageNode.Name : pageNode.Title,
				  GetNodeIcon(pageNode, "/umbraco/images/umbraco/edit.png"),
				  pageNode.Name,
				  " page");
		}

		public virtual void AddButtonToLiveEditingPannel(string pageId, string pageTitle, string imgSrc, string buttonText, string hoverToolTipText)
		{
			string onClickCode = string.Format("javascript:showEditNodeDialog('{0}','{1}')", pageId, pageTitle);
			string imageCode = string.Format("<input class = \"button\" type = \"image\" src= \"{0}\" onclick = \"{1}\" title = \"{2}\"/>", imgSrc, onClickCode, buttonText);
			string hyperlinkCode = string.Format("<span class=\"separator\"><span>&nbsp;</span></span><a href = \"javascript:void()\" onclick = \"{0}\" title = \"edit - {1} {4}, id:{3}\"><small>&nbsp; </small>{2}{1}</a>", onClickCode, buttonText, imageCode, pageId, hoverToolTipText);
			System.Web.UI.HtmlControls.HtmlGenericControl dvUmbLabelButton = new System.Web.UI.HtmlControls.HtmlGenericControl();
			dvUmbLabelButton.TagName = "div";
			dvUmbLabelButton.Attributes.Add("class", "umbLabelButton");
			dvUmbLabelButton.InnerHtml = hyperlinkCode;
			UmbracoContext.Current.LiveEditingContext.Menu.Add(dvUmbLabelButton);
		}

		private void AddScriptsToPage()
		{
			System.Web.UI.HtmlControls.HtmlGenericControl scriptControl = new System.Web.UI.HtmlControls.HtmlGenericControl();
			scriptControl.TagName = "span";
			scriptControl.Attributes.Add("class", "separator");
			scriptControl.InnerHtml = "<script type=\"text/javascript\">" +
					@"function showEditNodeDialog(pageId, pageTitle, width, height) {
						pageTitle = '-Editing: '+String(pageId)+'  [' + String(pageTitle) + ']';
						width = width && Number(width) > 0 ? width : 980;
						height = height && Number(height) > 0 ? height : 720;
						UmbClientMgr.openModalWindow('/umbraco/editContent.aspx?id=' + pageId, pageTitle, true, width, height);
					};" +
					"</script>";
			UmbracoContext.Current.LiveEditingContext.Menu.Add(scriptControl);
		}

		private string GetNodeIcon(IModuleNode pageNode, string defaultIcon)
		{
			INode ndata = (pageNode.Data as INode);
			if (ndata == null) return defaultIcon;
			ContentType ct = ContentType.GetByAlias(ndata.NodeTypeAlias);
			if (ct == null) return defaultIcon;
			return
				string.IsNullOrEmpty(ct.IconUrl) ? defaultIcon
				: ct.IconUrl.StartsWith(".") ? defaultIcon
				: "/umbraco/images/umbraco/" + ct.IconUrl;

		}
		#endregion

        private void EnsureModuleUmbracoSettings()
        {
          ///nothing here 
          ///Todo: possibility to reinstall module settings: nodes,content types, files etc.
        }
	}
}

